import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.Droite;
import pluginUtils.MobiusTransform;
import pluginUtils.CircleInversion;
import pluginUtils.PackCircle;
import pluginUtils.Point2D;
import pluginUtils.Pos3D;
import pluginUtils.Sphere;
import pluginUtils.SphereInversion;


public class GenericDrawerFaroHSB extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=10008,Y=10004; // image size
	
	private PrintStream output;
	private double xShift=0; 
	private double zShift=0; 
	private double limit,lmoins; 
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	

	private void drawCircle(Point2D C,double r){
		double xCenter=C.getX(); 
		double yCenter=C.getY(); 
	 
		
		int intX=(int)((xCenter)*acoef+ccoef);
		int intY=Y-(int)((yCenter)*vcoef+wcoef);
		int intRx=(int)(r*acoef);
		int intRy=(int)(r*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
	}
	

	private void drawPoint(double x,double y){
		int intX=(int)(x*acoef+ccoef);
		int intY=Y-(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	private void drawPoint(Point2D A){
		drawPoint(A.getX(),A.getY()); 
	}
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,Y-YD,XF,Y-YF); 
	}
	
	private void drawLine(Point2D A,Point2D B){
		drawLine(A.getX(),A.getY(),B.getX(),B.getY()); 
	}
		
	public static void affiche(int t[]){
		System.out.print("{");
		for(int i=0;i<t.length;i++){
			System.out.print(t[i]+" "); 
			if(i<t.length-1) System.out.print(","); 
		}
		System.out.println("},"); 
			
	}
	
	public static boolean isSorted(int t[]){
		for(int i=0;i<t.length;i++)
			if(t[i]!=i) return false; 
		return true; 
	}
	
	// calcule la longueur du cycle de faro pour 2*n cartes
	public static int makeFaro(int n){
		int tab[]=new int[2*n];
		int turn=0; 
		for(int i=0;i<2*n;i++) tab[i]=i;
		do{
			//affiche(tab); 
			int aux[]=new int[2*n]; 
			for (int j=0;j<n;j++)
				aux[2*j]=tab[j]; 
			for(int j=n;j<2*n;j++)
				aux[1+2*(j-n)]=tab[j];
		System.arraycopy(aux,0,tab, 0,2*n);
		turn++; 
		}while(!isSorted(tab));
		//affiche(tab); 
		return turn; 
	}
	
	public int[] faro(int[] src){
		int n=src.length; 
		int aux[]=new int[n]; 
		for (int j=0;j<n/2;j++)
			aux[2*j]=src[j]; 
		for(int j=n/2;j<n;j++)
			aux[1+2*(j-n/2)]=src[j];
		return aux; 
	}
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
	
		
		 limit=1; 
		 lmoins=0;
	
		setBounds(lmoins,limit,lmoins,limit); 
		setCoefs(); 
		
		
		
		
		
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(3); 
		
		drawLine(lmoins,0,limit,0); 
		drawLine(0,lmoins,0,limit); 

		setProcessor("Verifying", primeIP);
		show();
		System.out.println("debut"); 	
	
		int src[]=new int[X/2];
		for(int i=0;i<X/2;i++) src[i]=i; 
		for(int i=0;i<Y/2;i++){
				System.out.println(i); 
				// affichage de la ligne
				for(int j=0;j<src.length;j++){
					float convert=(2*src[j]+0.0f)/X; 
					primeIP.setColor(Color.HSBtoRGB(convert,0.8f,0.8f)); 
					primeIP.drawPixel(2*j,2*i); 
					primeIP.drawPixel(2*j,2*i+1); 
					primeIP.drawPixel(2*j+1,2*i); 
					primeIP.drawPixel(2*j+1,2*i+1); 
				}
				src=faro(src);
				if(isSorted(src))System.out.println("trié "+Y/2); 
				updateAndDraw(); 
		}
		
	
		 show();

	}	
}
	